package com.example.androidstudy.moshi

import com.squareup.moshi.Moshi
import okhttp3.MediaType
import okhttp3.ResponseBody
import okio.Buffer
import okio.BufferedSource
import okio.buffer
import okio.source
import retrofit2.Converter
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import java.io.ByteArrayInputStream
import java.lang.reflect.Type

class RetrofitMoshiFactory(
    val log: (String) -> Unit,
    val decryptWithAES: (ByteArray) -> ByteArray,
    val encryptWithAES: (ByteArray) -> ByteArray
) : Converter.Factory() {
    private val delegate = MoshiConverterFactory.create(
        Moshi.Builder().add(NullToEmptyListJsonAdapter.FACTORY)
            .add(NullToEmptyStringAdapter())
            .build()
    )

    inner class MyConvert(private val converter: Converter<ResponseBody, Any>) :
        Converter<okhttp3.ResponseBody, Any> {
        override fun convert(value: ResponseBody): Any {
            val contentLength = value.contentLength()
            val contentType = value.contentType()
            val bytes = decryptWithAES(value.bytes())
            val buffer = ByteArrayInputStream(bytes).source().buffer()
            log("MyConvert ${String(bytes)}")
            val convert = converter.convert(object : ResponseBody() {
                override fun contentType(): MediaType? = contentType

                override fun contentLength(): Long = contentLength

                override fun source(): BufferedSource {
                    return buffer
                }

            })!!
            return convert
        }
    }

    override fun responseBodyConverter(
        type: Type,
        annotations: Array<out Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, Any> {
        val converter = delegate.responseBodyConverter(type, annotations, retrofit)
        return MyConvert(converter as Converter<ResponseBody, Any>)
    }

    inner class RequestBodyConverter(private val converter: Converter<Any, okhttp3.RequestBody>) :
        Converter<Any, okhttp3.RequestBody> {
        override fun convert(value: Any): okhttp3.RequestBody {
            val convert = converter.convert(value)!!
            val buffer = Buffer()
            convert.writeTo(buffer)

            return okhttp3.RequestBody.create(
                convert.contentType(),
                encryptWithAES(buffer.readByteArray())
            )
        }
    }

    override fun requestBodyConverter(
        type: Type,
        parameterAnnotations: Array<out Annotation>,
        methodAnnotations: Array<out Annotation>,
        retrofit: Retrofit
    ): Converter<Any, okhttp3.RequestBody>? {
        return RequestBodyConverter(
            delegate.requestBodyConverter(
                type,
                parameterAnnotations,
                methodAnnotations,
                retrofit
            ) as Converter<Any, okhttp3.RequestBody>
        )
    }
}

